How to Run ZK on Apache + Tomcat clustering, Part II
Ian Tsai, Engineer, Potix Corporation
May 17, 2007
- Apache 2.2.4 latter
- Apache JK Connector 1.2.22
- Apache-Tomcat-5.5.X
- ZK freshly
- Eclipse3.2
Introduction
Last time in How to Run ZK on Apache + Tomcat clustering, Part I, I introduced how to build a simple environment to run ZK. This time I'll try to describe how ZK support clustering, and some issue should be take care while developing ZK component.
Container Management HttpSession Replication
In the case we build last time, although loadbalancing is already done by Apache JK module and the rest is just a little configuration, session replication is such a importent issue for component developer to pay attention.
Because ZK maintains an UI component model in each user's HttpSession Attribute, and server use this model to fully recognize the meaning of user's operation. We need to know which part definded in the HttpSession specification that helps ZK to replicate this model to other clustering nodes. (If you are not sure what HttpSession is, please read this and this.)
Java(TM) Servlet API Specification 2.2 guarantees that those Objects implement these two interfaces should be serialized by container if needed. this mechanism is used in session Virtual Memory System and Clustering system:
- java.io.Serializable
Session replication is based on object serialization. objects must implement serializable while transfering between jvms.
- avax.servlet.http.HttpSessionActivationListener
This interface's methods will fired by container while session replication between two containers is finished. this helps session objects to rebuild resource references.
ZK Session Object Serialization
In order to successfully start session replication function, Add this tag to the zk.xml:
<system-config>
<ui-factory-class>
org.zkoss.zk.ui.http.SerializableUiFactory
</ui-factory-class>
</system-config>
Which changes ZK's setting to use SerializableUiFactory, session created now (SerializableSession) will implement java.io.Serializable and javax.servlet.http.HttpSessionActivationListener. The session replication machanism implemented by container will synchronize user's session data to every cluster nodes. Picture shown bellow demonstrates what ZK stores in HttpSession.
Because ZK stores every user's session object(org.zkoss.zk.ui.Session) in HttpSession's Attribute(by use of httpSession.setAttribute(...)). While Servlet's GET POST method are invoked, ZK WebManager will get users session object from HttpSession.
- While Serialization: bidirect avoiding
As shown in ZK's user session model, ZK framework has bidirect references that will cause dead loop while serializing. This issue not only occurs in ZK but also happening in any object serialization works. ZK use keyword transient to cut off references. Let's take a code clip for example:
public class DesktopImpl implements Desktop, DesktopCtrl, java.io.Serializable {
private static final Log log = Log.lookup(DesktopImpl.class);
private static final long serialVersionUID = 20070416L;
/** Represents media. It must be distinguishable from component's ID. */
private static final String MEDIA_PREFIX = "med";
private transient WebApp _wapp;
private transient Session _sess;
private String _id;
/** The current directory of this desktop. */
private String _dir;
/** The URI to access the update engine. */
private final String _updateURI;
/** Map(String id, Page page). */
private final Map _pages = new LinkedHashMap(3);
- While De-Serialization: transient reference & local resource reference rebuild
Those references we cut off before and those local resource that miss linked must be handled now. ZK's SerializableSession and use a method chain sessionDidActivate(...) to accomplish this requirement. Detailed infomation is shown in next topic.
Notice of developing serializable ZK Component
1.Extends org.zkoss.zk.ui.AbstractComponent, Mostly extends AbstractComponent will be more convenient.
2.Set transient to fields that you would not serialized. For example, database Connection pool and thread pool.
3.Rebuild the resource's reference you cut off. Overrides "public void sessionDidActivate(Page page)" method like this:
public void sessionDidActivate(Page page) {
super.sessionDidActivate(page);
// write you implementation here...
}
Because AbstractComponent.sessionDidActivate(page) provides a DFS(Depth First Search) recursive call to rebuild child component's parent reference, while write your implementation code befor, call super method first.
zkDemo in clustering
Here is an easy failover test for zkdemo. Before our step by step, Tomcat MCast service must be set properly. please remember to ensure your computer is connected to a Hub or something to make your Ethernet Card could receive it's own package.
1.Start Apache server + Tomcat Node 1.
Following last time I demonstrated you'll see such messages like this:
Info: Register manager /zkdemo to cluster element Host with name localhost 2007/5/19 PM 02:04:39 org.apache.catalina.cluster.session.DeltaManager start Info: Starting clustering manager at /zkdemo 2007/5/19 PM 02:04:39 org.apache.catalina.cluster.session.DeltaManager getAllClusterSessions Info: Manager [/zkdemo]: skipping state transfer. No members active in cluster group. 2007/5/19 PM 02:04:39 org.zkoss.zk.ui.sys.ConfigParser parse:56 Info: Parsing jndi:/localhost/zkdemo/WEB-INF/zk.xml 2007/5/19 PM 02:04:40 org.zkoss.zk.ui.sys.ConfigParser parseClass:257 Info: Using org.zkoss.zk.ui.http.SerializableUiFactory for interface org.zkoss.zk.ui.sys.UiFactory 2007/5/19 PM 02:04:40 org.apache.coyote.http11.Http11BaseProtocol start Info: Starting Coyote HTTP/1.1 on http-8080
2.Browse http://localhost/zkdemo and do some operation. Thus ZK will create some components in Session.
3.Start Tomcat Node 2.
While starting Node 2, this instance will broadcast its self to net and try to find other members. If finded and successfully joining to the membership, other members will replicate their Sessions to this new member. The messages are like these:
Tomcat Node 1
2007/5/19 PM 02:15:17 org.apache.catalina.cluster.tcp.SimpleTcpCluster memberAdded Info: Replication member added:org.apache.catalina.cluster.mcast.McastMember [tcp://10.1.3.57:4001,catalina,10.1.3.57,4001, alive=0] 2007/5/19 PM 02:15:17 org.apache.catalina.cluster.tcp.FastAsyncSocketSender checkThread Info: Create sender [/10.1.3.57:4,001] queue thread to tcp background replication 2007/5/19 PM 02:15:20 org.apache.catalina.cluster.tcp.SimpleTcpCluster logSendMessage Info: SEND 2007/5/19:U 02:15:20 0 10.1.3.57:4,001 SESSION-STATE-/zkdemo 2007/5/19 PM 02:15:20 org.apache.catalina.cluster.tcp.SimpleTcpCluster logSendMessage Info: SEND 2007/5/19:U 02:15:20 0 10.1.3.57:4,001 SESSION-STATE-TRANSFERED/zkdemo 2007/5/19 PM 02:15:20 org.apache.catalina.cluster.tcp.SimpleTcpCluster logReceiveMessage Info: RECEIVE 2007/5/19:U 02:15:19 484 10.1.3.57:4,001 GET-ALL-/zkdemo true
Tomcat Node 2
2007/5/19 PM 02:15:15 org.apache.catalina.cluster.mcast.McastService start Info: Sleeping for 2000 milliseconds to establish cluster membership 2007/5/19 PM 02:15:15 org.apache.catalina.cluster.tcp.SimpleTcpCluster memberAdded Info: Replication member added:org.apache.catalina.cluster.mcast.McastMember [tcp://10.1.3.57:4002,catalina,10.1.3.57,4002, alive=639016] 2007/5/19 PM 02:15:16 org.apache.catalina.cluster.tcp.FastAsyncSocketSender checkThread Info: Create sender [/10.1.3.57:4,002] queue thread to tcp background replication 2007/5/19 PM 02:15:17 org.apache.catalina.cluster.mcast.McastService registerMBean Info: membership mbean registered (Catalina:type=ClusterMembership,host=localhost) .... 2007/5/19 PM 02:15:19 org.apache.catalina.cluster.tcp.SimpleTcpCluster logSendMessage Info: SEND 2007/5/19:U 02:15:19 16 10.1.3.57:4,002 GET-ALL-/zkdemo 2007/5/19 PM 02:15:19 org.apache.catalina.cluster.session.DeltaManager getAllClusterSessions Attention!: Manager [/zkdemo], requesting session state from org.apache.catalina.cluster.mcast.McastMember [tcp://10.1.3.57:4002,catalina,10.1.3.57,4002, alive=642532]. This operation will timeout if no session state has been received within 60 seconds. 2007/5/19 PM 02:15:22 org.apache.catalina.cluster.tcp.SimpleTcpCluster logReceiveMessage Info: RECEIVE 2007/5/19:U 02:15:20 2,250 10.1.3.57:4,002 SESSION-STATE-/zkdemo true 2007/5/19 PM 02:15:22 org.apache.catalina.cluster.tcp.SimpleTcpCluster logReceiveMessage Info: RECEIVE 2007/5/19:U 02:15:22 0 10.1.3.57:4,002 SESSION-STATE-TRANSFERED/zkdemo true
4.Shutdown Tomcat Node 1. At the first step, we browse zkdemo at Node1, now we turn off it, the service now should provided by Node 2.
2007/5/19 PM 03:11:52 org.apache.catalina.cluster.tcp.SimpleTcpCluster memberDisappeared Info: Received member disappeared:org.apache.catalina.cluster.mcast.McastMember [tcp://10.1.3.57:4001,catalina,10.1.3.57,4001, alive=3391890] 2007/5/19 PM 03:11:52 org.apache.catalina.cluster.util.FastQueue remove Info: FastQueue.remove: Remove aborted although queue enabled
5.Use the same browser and do more operation, seeing any different. There is nothing different in browser side because session is successfully replicated to Node 2.
Summary
ZK holds users data in HttpSession to use container managment functionality to do session replication. Correct setting in zk.xml, make sure component extends AbstractComponent and overrides sessionDidActivate(page) method will make component survive in clustering environment.
Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License. |